<template>
  <div class="containerBox" :key="showType">
    <div :id="showType" :style="containerBoxStyle"></div>
    <CustomPropertiesPanel v-if="panelVisible" :data="clickNodeFrom" @submit="submit" @cancel="cancel"></CustomPropertiesPanel>
    <!-- <div id="js-properties-panel" class="panel"></div> -->
  </div>
</template>
<script setup lang="ts" name="Process">
import { onMounted, markRaw, watch, ref, computed } from "vue";

// bpmn-js相关

import "bpmn-js/dist/assets/diagram-js.css"; // 左边工具栏以及编辑节点的样式

import "bpmn-js/dist/assets/bpmn-font/css/bpmn-embedded.css";

import BpmnModeler from "bpmn-js/lib/Modeler";

// bpmn-js-properties-panel相关

import "bpmn-js-properties-panel/dist/assets/bpmn-js-properties-panel.css";

// import propertiesPanelModule from "bpmn-js-properties-panel";*

import propertiesProviderModule from "bpmn-js-properties-panel/lib/provider/camunda";

import camundaModdleDescriptor from "camunda-bpmn-moddle/resources/camunda.json";
// 引入汉化js
import translate from "@/assets/bpmn/translate.js";
// 自定义模块
import customControlsModule from "./customPanel";
import CustomPropertiesPanel from "./panel/customPropertiesPanel.vue";
import _ from "lodash";
import { ElMessage } from "element-plus";
const props = defineProps({
  save: {
    type: Boolean,
    default: false
  },
  width: {
    type: String,
    default: "100%"
  },
  height: {
    type: String,
    default: "430px"
  },
  xmlStr: {
    type: String as any,
    default: null
  },
  showType: {
    type: String,
    default: "OPERATE"
  },
  data: {
    type: Array,
    default: () => []
  }
});
const containerBoxStyle: any = computed(() => {
  return {
    width: props.width,
    height: props.height,
    position: "relative",
    border: "1px solid rgb(121 121 121)"
  };
});
const progressData = ref<any>([]);
const nodeDataTemp = ref<any>([]);

let customTranslateModule = {
  translate: ["value", translate]
};
const emit = defineEmits(["submitNode", "submitProcess"]);

let bpmnModeler = ref<any>();
const panelVisible = ref(false);
const eventBus = ref<any>();
let clickNodeFrom = ref<any>({
  type: props.showType,
  name: "",
  node_id: "",
  receive_type: "USER",
  receiver: [],
  approve_type: "APPROVE_ONE",
  desc: ""
});
// 导入xml数据
const createNewDiagram = async bpmn => {
  try {
    await bpmnModeler.value.importXML(bpmn);
  } catch (e) {
    ElMessage.warning("打开模型出错，数据格式有误！");
    console.log(e);
  }
};

//初始化BPMN内容，此处从后端获取，若需要改为从前端获取，请自行修改
const initCurrentBpmn = async () => {
  bpmnModeler.value = null;
  const containerEl = document.getElementById(props.showType);
  //创建新对象，去渲染相关内容
  bpmnModeler.value = markRaw(
    new BpmnModeler({
      container: containerEl,
      additionalModules: [customControlsModule, customTranslateModule, propertiesProviderModule],
      moddleExtensions: {
        camunda: camundaModdleDescriptor
      }
    })
  );
  if (props.xmlStr) {
    await createNewDiagram(props.xmlStr);
  } else {
    try {
      await bpmnModeler.value.createDiagram();
      bpmnModeler.value.get("canvas").zoom("fit-viewport");
    } catch (err) {
      console.log(err);
    }
  }
};

// 监听双击节点事件
const registerEventRoot = () => {
  // 给开始节点设置默认名称
  try {
    eventBus.value = bpmnModeler.value.get("eventBus");
    eventBus.value.on("shape.added", function (event) {
      const element = event.element;
      if (element.type === "bpmn:StartEvent" && !element.businessObject.name) {
        const modeling = bpmnModeler.value.get("modeling");
        setTimeout(() => {
          modeling.updateLabel(element, "开始");
        }, 500);
      }
    });
    const lastClickTime = ref(0);
    eventBus.value.on("element.click", e => {
      const element = e.element;
      const now = new Date().getTime();
      const diff = now - lastClickTime.value;
      if (diff < 300) {
        // 300ms 内认为是双击
        // 这里执行双击的逻辑
        if (!(element.type === "bpmn:StartEvent" || element.type === "bpmn:EndEvent" || element.type === "bpmn:Process")) {
          // 判断该节点是否提交过
          const index = nodeDataTemp.value.findIndex(item => item.node_id === element.id);
          if (index > -1) {
            clickNodeFrom.value = nodeDataTemp.value[index];
          } else {
            clickNodeFrom.value = {
              node_id: element.id,
              name: element.businessObject.name,
              type: props.showType,
              receive_type: "USER",
              receiver: [],
              approve_type: "APPROVE_ONE"
            };
          }
          panelVisible.value = true;
        }
      } else {
        // 这里执行单击的逻辑
      }
      lastClickTime.value = now;
    });
  } catch (error) {
    console.log(error);
  }
};

const submit = fromData => {
  // 提交节点信息到暂存
  const index = nodeDataTemp.value.findIndex(item => item.node_id === fromData.node_id);
  if (index > -1) {
    nodeDataTemp.value[index] = fromData;
  } else {
    nodeDataTemp.value.push(fromData);
  }
  panelVisible.value = false;
};

const cancel = () => {
  panelVisible.value = false;
};

// 保存流程图信息progressData
const saveProcess = () => {
  const elementRegistry = bpmnModeler.value.get("elementRegistry");
  const data = elementRegistry.filter(item => item.type === "bpmn:SequenceFlow");
  const startEvent = elementRegistry.filter(item => item.type === "bpmn:StartEvent");
  const endEvent = elementRegistry.filter(item => item.type === "bpmn:EndEvent");
  const UserTask = elementRegistry.filter(item => item.type === "bpmn:UserTask");
  let flag = false;
  if (startEvent.length == 1 && endEvent.length == 1 && UserTask.length > 0) {
    flag = true;
  }
  if (flag) {
    let progressTemp: any = [];
    data.map(item => {
      if (item.source && item.source.type !== "bpmn:EndEvent" && item.source.type !== "bpmn:StartEvent") {
        const { id, name } = item.source;
        progressTemp.push({ node_id: id, name: name });
      }
      if (item.target && item.target.type !== "bpmn:EndEvent" && item.target.type !== "bpmn:StartEvent") {
        const { id, name } = item.target;
        progressTemp.push({ node_id: id, name: name });
      }
    });
    progressData.value = _.uniqWith(progressTemp, _.isEqual);
  }
  verifyFrom();
};

// 总提交检查是否每个节点信息保存完成，并且流程图绘制完成
const verifyFrom = async () => {
  if (progressData.value.length) {
    progressData.value.forEach(function (progress) {
      nodeDataTemp.value.forEach(function (node) {
        if (progress.node_id === node.node_id) {
          Object.assign(progress, node);
          if (!node.node_id) {
            progress["node_id"] = progress.id;
            delete progress.id;
          }
        }
      });
    });
    console.log("节点信息", progressData.value);
    let hasEmpty = progressData.value.some(obj => !obj.receiver || obj.receiver.length === 0);
    if (hasEmpty) {
      props.showType === "OPERATE"
        ? ElMessage.error("请填写业务处理流程节点信息")
        : ElMessage.error("请填写业务审核流程节点信息");
      emit("submitNode", [], props.showType, "");
    } else {
      const xml = await downloadXml();
      emit("submitNode", progressData.value, props.showType, xml);
    }
  } else {
    emit("submitNode", [], props.showType, "");
  }
};
// 保存画布数据
const downloadXml = async () => {
  const data = await bpmnModeler.value.saveXML({ format: true });
  return data;
};
watch(
  () => props.save,
  val => {
    if (val) {
      // 生成流程图数据
      saveProcess();
    }
  }
);
watch(
  () => props.showType,
  val => {
    if (val) {
      initCurrentBpmn();
      registerEventRoot();
      saveProcess();
    }
  }
);
watch(
  () => props.xmlStr,
  async () => {
    if (bpmnModeler.value) {
      await bpmnModeler.value.createDiagram();
      createNewDiagram(props.xmlStr);
    }
  },
  {
    immediate: true,
    deep: true
  }
);
watch(
  () => props.data,
  val => {
    if (val) {
      nodeDataTemp.value = val;
    }
  },
  {
    immediate: true,
    deep: true
  }
);
onMounted(() => {
  initCurrentBpmn();
  registerEventRoot();
});
</script>

<style lang="scss" scoped>
.containerBox {
  position: relative;
  height: 450px;
  margin-top: 24px;
}
.bpp-properties-panel [type="text"] {
  box-sizing: border-box;
}
.panel {
  position: absolute;
  top: 1px;
  right: 1px;
  width: 400px;
  height: 100%;
  overflow: auto;
}

/* 右下角logo */
.bjs-powered-by {
  display: none;
}
</style>
